#include "shadow_page_table.h"
#include "memory.h"
#include "string.h"
#include "global.h"
#include "print.h"
#include "PF_handler.h"
#include "keyboard.h"

uint32_t* find_shadow_page_table(struct vcpu* vm_struct) 
{
    int count = 0;
    while (count < (vm_struct->shadow_pt_map_->shadow_page_table_count)) {
        if ((uint32_t)vm_struct->cr3 == (uint32_t)(vm_struct->shadow_pt_map_->shadow_page_table[count].guest_pt_phy_addr)) {
            return (uint32_t*)(vm_struct->shadow_pt_map_->shadow_page_table[count].shadow_pt_virtual_addr);
        }
        count++;
    }
    return NULL;
}


uint32_t* create_shadow_page_table(struct vcpu* vm_struct) 
{
    uint32_t cr3_ = get_cr3();
    //asm volatile ("movl %0, %%cr3" : : "r" ((uint32_t)(0x100000)) : "memory");   //更新页目录寄存器cr3,使新页表生效
    uint32_t guest_page_table_phyaddr = vm_struct->cr3;
    asm volatile ("movl %0, %%cr3" : : "r" ((uint32_t)addr_v2p((uint32_t)vm_struct->vm_phy_page_table)) : "memory");   //更新页目录寄存器cr3,使页表生效

    uint32_t* page_dir_vaddr = get_kernel_pages(1);
    if (page_dir_vaddr == NULL) {
        return NULL;
    }
    memcpy((uint32_t*)((uint32_t)page_dir_vaddr + 768 * 4), (uint32_t*)(0xfffff000 + 768 * 4), 255 * 4);
    uint32_t new_page_dir_phy_addr = addr_v2p((uint32_t)page_dir_vaddr);  
    page_dir_vaddr[1023] = new_page_dir_phy_addr | PG_US_S | PG_RW_W | PG_P_1; 

    int count = 0x0;
    for (;count < 1023; count++) {
        if (*((uint32_t*)(guest_page_table_phyaddr + (count * 4))) & 1) {

            uint32_t* pde_ = get_kernel_pages(1);
            uint32_t pde_phy_addr = addr_v2p((uint32_t)pde_);
            
            page_dir_vaddr[count] = pde_phy_addr | PG_US_U | PG_RW_W | PG_P_1;

            uint32_t guest_pde = (*((uint32_t*)(guest_page_table_phyaddr + (count * 4)))) & 0xFFFFF000;
            int count_1 = 0x0;

            for (;count_1 < 1024; count_1++) {
                if (*((uint32_t*)(guest_pde + (count_1 * 4))) & 1) {

                    uint32_t shadow_ptr_phy = addr_v2p((uint32_t)(*((uint32_t*)(guest_pde + (count_1 * 4))) & 0xFFFFF000));
                    if (shadow_ptr_phy == 0x0) {
                        continue;
                    }
                    pde_[count_1] = shadow_ptr_phy | PG_US_U | PG_RW_W | PG_P_1;
                }
            }
        }
    }
    if (vm_struct->shadow_pt_map_ == NULL) {
        vm_struct->shadow_pt_map_ = (struct shadow_pt_map*)get_kernel_pages(1);
        vm_struct->shadow_pt_map_->shadow_page_table_count = 0x0;
    } 
    vm_struct->shadow_pt_map_->shadow_page_table[vm_struct->shadow_pt_map_->shadow_page_table_count].guest_pt_phy_addr = guest_page_table_phyaddr;
    vm_struct->shadow_pt_map_->shadow_page_table[vm_struct->shadow_pt_map_->shadow_page_table_count].shadow_pt_virtual_addr = (uint32_t)page_dir_vaddr;
    vm_struct->shadow_pt_map_->shadow_page_table_count++;
    asm volatile ("movl %0, %%cr3" : : "r" (cr3_) : "memory"); 
    // // put_int((uint32_t)page_dir_vaddr);

    // asm("jmp .");
    return (uint32_t*)page_dir_vaddr;

}

void memory_map_G(struct vcpu* vm_struct)
{
    uint32_t cr3_ = get_cr3();
    uint32_t guest_page_table_phyaddr = vm_struct->cr3;
    int count = 0x0;
    int count_num = 0x0;

    asm volatile ("movl %0, %%cr3" : : "r" ((uint32_t)addr_v2p((uint32_t)vm_struct->vm_phy_page_table)) : "memory");
    memcpy(0xc00b8000, 0xb8000, 0x8000);
    

    for (;count <  8; count++ ) {
        phy_addr[count] = *((uint32_t*)(0xffc002e0 + (count * 4)));
    }

    if (guest_page_table_phyaddr) {
        while (count_num < (vm_struct->shadow_pt_map_->shadow_page_table_count)) {
            guest_page_table_phyaddr = (uint32_t)(vm_struct->shadow_pt_map_->shadow_page_table[count_num].guest_pt_phy_addr);
            uint32_t shadow_pt = (uint32_t)(vm_struct->shadow_pt_map_->shadow_page_table[count_num].shadow_pt_virtual_addr);
            count = 0x0;
            for (;count < 1023; count++) {
                if (*((uint32_t*)(guest_page_table_phyaddr + (count * 4))) & 1) {

                    uint32_t guest_pde = (*((uint32_t*)(guest_page_table_phyaddr + (count * 4)))) & 0xFFFFF000;
                    int count_1 = 0x0;

                    for (;count_1 < 1024; count_1++) {
                        if (*((uint32_t*)(guest_pde + (count_1 * 4))) & 1) {
                            switch (*((uint32_t*)(guest_pde + (count_1 * 4))) & 0xFFFFF000) {
                                case 0xb8000:
                                asm volatile ("movl %0, %%cr3" : : "r" ((uint32_t)addr_v2p((uint32_t)shadow_pt)) : "memory");
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xb8 * 4))) = (0xb8000) | PG_US_U | PG_RW_W | PG_P_1;
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xb9 * 4))) = (0xb9000) | PG_US_U | PG_RW_W | PG_P_1;
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xba * 4))) = (0xba000) | PG_US_U | PG_RW_W | PG_P_1;
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbb * 4))) = (0xbb000) | PG_US_U | PG_RW_W | PG_P_1;
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbc * 4))) = (0xbc000) | PG_US_U | PG_RW_W | PG_P_1;
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbd * 4))) = (0xbd000) | PG_US_U | PG_RW_W | PG_P_1;
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbe * 4))) = (0xbe000) | PG_US_U | PG_RW_W | PG_P_1;
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbf * 4))) = (0xbf000) | PG_US_U | PG_RW_W | PG_P_1;
                                asm volatile ("movl %0, %%cr3" : : "r" ((uint32_t)addr_v2p((uint32_t)vm_struct->vm_phy_page_table)) : "memory");
                                break;
                                
                            }
                        }
                    }
                }
            }
            count_num++;

        }
    } else {
        count = 0x0;
        for (;count <  8; count++ ) {
            *((uint32_t*)(0xffc002e0 + (count * 4))) = (0xb8000 + (count * 0x1000)) | PG_US_U | PG_RW_W | PG_P_1;
        }
    }

    asm volatile ("movl %0, %%cr3" : : "r" (cr3_) : "memory");
}

void memory_map_H(struct vcpu* vm_struct)
{
    uint32_t cr3_ = get_cr3();
    uint32_t guest_page_table_phyaddr = vm_struct->cr3;
    int count = 0x0;
    int count_num = 0x0;

    asm volatile ("movl %0, %%cr3" : : "r" ((uint32_t)addr_v2p((uint32_t)vm_struct->vm_phy_page_table)) : "memory");
    for (;count <  8; count++ ) {
        *((uint32_t*)(0xffc002e0 + (count * 4))) = phy_addr[count];
    }
    memcpy(0xb8000, 0xc00b8000, 0x8000);

    if (guest_page_table_phyaddr) {
        while (count_num < (vm_struct->shadow_pt_map_->shadow_page_table_count)) {
            guest_page_table_phyaddr = (uint32_t)(vm_struct->shadow_pt_map_->shadow_page_table[count_num].guest_pt_phy_addr);
            uint32_t shadow_pt = (uint32_t)(vm_struct->shadow_pt_map_->shadow_page_table[count_num].shadow_pt_virtual_addr);
            count = 0x0;
            for (;count < 1023; count++) {
                if (*((uint32_t*)(guest_page_table_phyaddr + (count * 4))) & 1) {

                    uint32_t guest_pde = (*((uint32_t*)(guest_page_table_phyaddr + (count * 4)))) & 0xFFFFF000;
                    int count_1 = 0x0;

                    for (;count_1 < 1024; count_1++) {
                        if (*((uint32_t*)(guest_pde + (count_1 * 4))) & 1) {
                            switch (*((uint32_t*)(guest_pde + (count_1 * 4))) & 0xFFFFF000) {
                                case 0xb8000:
                                asm volatile ("movl %0, %%cr3" : : "r" ((uint32_t)addr_v2p((uint32_t)shadow_pt)) : "memory");
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xb8 * 4))) = phy_addr[0];
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xb9 * 4))) = phy_addr[1];
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xba * 4))) = phy_addr[2];
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbb * 4))) = phy_addr[3];
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbc * 4))) = phy_addr[4];
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbd * 4))) = phy_addr[5];
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbe * 4))) = phy_addr[6];
                                *((uint32_t*)(0xffc00000 + (count * 0x1000) + (0xbf * 4))) = phy_addr[7];
                                asm volatile ("movl %0, %%cr3" : : "r" ((uint32_t)addr_v2p((uint32_t)vm_struct->vm_phy_page_table)) : "memory");
                                break;
                                
                            }
                        }
                    }
                }
            }
            count_num++;

        }
    }
    asm volatile ("movl %0, %%cr3" : : "r" (cr3_) : "memory");
}

